iT邦幫忙

2022 iThome 鐵人賽

DAY 17
3
Software Development

React框架白話文運動系列 第 17

React白話文運動17-React Hook-useContext 01

  • 分享至 

  • xImage
  •  

前言

嗨,我是Hogan
目前在經營自己的自媒體 hogan.tech
主要分享一些有關於程式碼、軟體和科技業經驗分享
有興趣的讀者可以進一步關注我,進而獲得更多資訊唷!

未來文章一併更新於此網站 Hogan.B Lab
並且包含多語系 繁體中文英文日文簡體中文
觀看分類:React 白話文運動其他系列

如果想要快速查找其他文章請點選目錄

成立 hogan.tech 的初衷是
希望每個正在這條路上探索的人,
都可以透過 Hogan.tech 嘗試進入程式領域。


前一篇介紹新的hook,useRef

  1. 建構表單
  2. 使用React Ref
  3. 受控元件(Controlled Component)

這一篇則是會介紹另一個hook,useContext

不過在介紹 useContext 之前,則是會介紹元件樹的狀態管理

  1. 狀態傳遞:由上而下
  2. 狀態傳遞:由下而上
  3. 狀態管理:Context

狀態傳遞:由上而下

這邊我使用之前的 StarRating 元件來實作,狀態由父元件傳至子元件的狀態管理

基本上都是透過元件的參數傳遞由上傳遞至下

App.jsx

const colorData = [
    { id: "1", title: "red", color: "red", rating: 5 },
    { id: "2", title: "blue", color: "blue", rating: 2 },
    { id: "3", title: "green", color: "green", rating: 4 },
]
export default function App() {
    const [colors] = useState(colorData)
    return <ColorList colors={colors}></ColorList>
}

這邊先訂一組 Json 資料,並且在父元件使用 useState 去做狀態的宣告

也將此資料傳入 ColorList 元件

ColorList.jsx

export default function ColorList({ colors = [] }) {
    if (!colors.length) return <div>No colors</div>;
    return (
        <div>
            {colors.map(color => <Color key={color.id} {...color} />)}
        </div>
    )
}

透過傳入的 colorData 先判斷陣列是否有資料,沒有資料的話顯示 No colors

否則根據這些資料,再次傳入 Color 子元件

Color.jsx

export default function Color({ title, color, rating }) {
    return (
        <section>
            <h1>{title}</h1>
            <div style={{ height: 50, width: 50, backgroundColor: color }}></div>
            <StarRating selectedStars={rating} />
        </section>
    )
}

透過 ColorList 父元件傳入的資料,分別有 title、color 、rating

分別顯示在不同的位子,其中也在 div 區塊,使用css style 顯示顏色

也透過 rating 傳入到最後的 StarRating 顯示星星數

StarRating.jsx

const Star = ({ selected = true, onSelect = f => f }) => (
    <FaStar color={selected ? 'red' : 'gray'} onCLick={onSelect}></FaStar>
)

const createArray = length => [...Array(length)];

export default function StarRating({ totalStars = 5, selectedStars = 0 }) {
    return <div>
        {createArray(totalStars).map((n, i) =>
            <Star
                key={i}
                selected={selectedStars > i}
               />
        )}
        <p>
            {selectedStars} of {totalStars} stars
        </p>
    </div>
}

image


狀態傳遞:由下而上

由 props 可以做到父元件到子元件的參數傳遞,但如果我們希望子元件按下刪除按鈕,就可以刪除元件呢?

我們就需要再透過傳遞函數的方式,在子元件一一回傳,並且使用 useState 中的 setState 來去操作

Color.jsx

export default function Color({ id, title, color, rating, onRemove = f => f }) {
    return (
        <section>
            <h1>{title}</h1>
            <button onClick={() => onRemove(id)}>
                <FaTrash />
            </button>
            <div style={{ height: 50, width: 50, backgroundColor: color }}></div>
            <StarRating selectedStars={rating} />
        </section >
    )
}

先在 Color 元件新增一個callback function 叫做 onRemove

只要點擊此按鈕,就會觸發一次 onRemove

ColorList.jsx

export default function ColorList({ colors = [], onRemoveColor = f => f }) {
    if (!colors.length) return <div>No colors</div>;
    return (
        <div style={{ padding: 100 }}>
            {colors.map(color => <Color key={color.id} {...color} onRemove={onRemoveColor} />)}
        </div>
    )
}

再到上一層的父原件,一樣新增一個 callback function 叫做 onRemoveColor,並且將此函數往下傳遞

App.jsx

export default function App() {
    const [colors, setColors] = useState(colorData)
    return <ColorList colors={colors} onRemoveColor={
        id => {
            const newColors = colors.filter(color => color.id !== id);
            setColors(newColors)
        }
    } ></ColorList>
}

最後在最上層的父原件,定義好 onRemoveColor 需要做哪些事情

這邊做了兩件事情,透過子元件回傳的 id,將陣列過濾

最後在使用 setColors 將狀態更新


狀態管理:Context

講完了狀態由上至下以及由下至上,應該不難發現,如果今天我們的元件很多層

我們就必須要在有經過的元件,一直將參數做傳遞,這是一件非常麻煩且冗長的事情

React 因此也有了另一種狀態管理,稱為Context

可以想像成,我們把每一層元件全部包起來,只要在裡面任何元件有使用到的地方,只要在該元件做使用就好,不需要再一層一層的傳遞

如果要用日常生活來比喻的話

由上至下、由下至上就像是火車,如果要從一個火車站傳遞貨物到終點站,需要一站一站的經過

Context 則是像飛機,如果要從一個機場傳遞貨物到終點站,則可以直接傳送資料到該目的地

接續會深入講解 Context 的寫法以及 Context Provider 的用法


結語

這一篇比較了幾種不同的 React 狀態管理,由上而下、由下而上、Context

下一篇就會深入講解Context 的概念與實作

如果有任何建議與疑問也歡迎留言!

如果喜歡此系列文章,請不吝於按下喜歡及分享,讓更多人看到唷~


上一篇
React白話文運動16-React Hook-useRef
下一篇
React白話文運動18-React Hook-useContext 02
系列文
React框架白話文運動30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言